package cn.xuqiudong.sso.server.session.impl;

import cn.xuqiudong.sso.common.model.AccessTokenContent;
import cn.xuqiudong.sso.common.model.AuthorizationCode;
import cn.xuqiudong.sso.server.config.SsoConfiguration;
import cn.xuqiudong.sso.server.session.AccessTokenManager;
import cn.xuqiudong.sso.server.storage.StorageStrategy;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Set;

/**
 * 描述:
 *          本地AccessToken管理器
 * @author Vic.xu
 * @since 2021-11-02 11:25
 */
@Component
public class AccessTokenManagerImpl implements AccessTokenManager {


    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private SsoConfiguration ssoConfiguration;

    @Resource
    private StorageStrategy<AccessTokenContent> accessTokenContentStorageStrategy;


    /**
     * AccessToken 的过期时间是refreshToken的一半
     * @return
     */
    @Override
    public int expire() {
        return ssoConfiguration.getAccessTokenTimeout();
    }

    @Override
    public String cacheName() {
        return "access-token";
    }

    public String tgtAndAtCacheName() {
        return cacheName() + "s:with-tgt";
    }

    @Override
    public void storage(String accessToken, AccessTokenContent tokenInfo) {
        accessTokenContentStorageStrategy.storage(cacheName(), accessToken, tokenInfo, expire());
//        tgtAndAccessTokensMap.computeIfAbsent(tokenInfo.getAuthorizationCode().getTgt(), a -> new HashSet<>()).add(accessToken);
        String tgt = tokenInfo.getAuthorizationCode().getTgt();
        accessTokenContentStorageStrategy.storage2SetData(tgtAndAtCacheName(), tgt, accessToken);
        logger.info("调用凭证存储成功, accessToken:{}, 并保存到tgt对应的缓存,tgt：{}", accessToken, tgt);
    }

    @Override
    public boolean refresh(String accessToken) {
        return accessTokenContentStorageStrategy.refresh(cacheName(), accessToken, expire(), AccessTokenContent.class) != null;
    }

    @Override
    public AccessTokenContent get(String accessToken) {
        return accessTokenContentStorageStrategy.getData(cacheName(), accessToken, AccessTokenContent.class);

    }

    /**
     * 根据tgt  删除  accessToken
     * @param tgt
     */
    @Override
    public void remove(String tgt) {
        Set<String> accessTokenSet = accessTokenContentStorageStrategy.getSetData(tgtAndAtCacheName(), tgt);
        if (CollectionUtils.isEmpty(accessTokenSet)) {
            return;
        }
        accessTokenSet.forEach(accessToken -> {
            AccessTokenContent accessTokenInfo = get(accessToken);
            if (accessTokenInfo == null) {
                // TODO 从set中删除
                return;
            }
            AuthorizationCode authorizationCode = accessTokenInfo.getAuthorizationCode();
            if (authorizationCode == null || !authorizationCode.isNotifyLogout()) {
                return;
            }
            String logoutUrl = ssoConfiguration.getLogoutUrl(accessTokenInfo.getAppId());
            if (StringUtils.isBlank(logoutUrl)) {
                //没有配置登出地址 则使用登录时候传来的重定向地址
                logoutUrl = authorizationCode.getRedirectUri();
            }
            logger.debug("发起客户端登出请求, accessToken:{}, url:{}", accessToken, logoutUrl);
            sendLogoutRequest(logoutUrl, accessToken);
        });
    }
}
